<?php

namespace Wxpay\jinjian;

use Wxpay\jinjian\Services\Api\WechatApi3;
use Wxpay\jinjian\Services\Traits\Certificate;
use Wxpay\jinjian\Services\Traits\UploadMedia;

class Wechat extends BaseWechat implements WechatApi3
{

    use UploadMedia;
    use Certificate;

    /**
     * applyEnter 申请入驻小微商户
     * @return mixed
     */
    public function applyEnterv3(array $params)
    {
        $url = self::WXAPIHOST . '/applyment4sub/applyment/';
        $data = [
            'business_code' => $params['business_code'],
            'contact_info' => [
                'contact_name' => $this->Encrypt($params['contact_name']),
                'contact_id_number' => $this->Encrypt($params['contact_id_number']),
                'mobile_phone' => $this->Encrypt($params['mobile_phone']),
                'contact_email' => $this->Encrypt($params['contact_email'])
            ],
            'subject_info' => [
                'subject_type' => $params['subject_type'],
                'business_license_info' => [
                    'license_copy' => $params['license_copy'],
                    'license_number' => $params['license_number'],
                    'merchant_name' => $params['merchant_name'],
                    'legal_person' => $params['legal_person']
                ],
                'identity_info' => [
                    'id_doc_type' => $params['id_doc_type'],
                    'id_card_info' => [
                        'id_card_copy' => $params['id_card_copy'],
                        'id_card_national' => $params['id_card_national'],
                        'id_card_name' => $this->Encrypt($params['id_card_name']),
                        'id_card_number' => $this->Encrypt($params['id_card_number']),
                        'card_period_begin' => $params['card_period_begin'],
                        'card_period_end' => $params['card_period_end']
                    ],
                    'owner' => $params['owner'] ? true : false
                ]
            ],
            'business_info' => [
                'merchant_shortname' => $params['merchant_shortname'],
                'service_phone' => $params['service_phone'],
                'sales_info' => [
                    'sales_scenes_type' => [
                        $params['sales_scenes_type']
                    ],
                    'biz_store_info' => [
                        'biz_store_name' => $params['biz_store_name'],
                        'biz_address_code' => $params['biz_address_code'],
                        'biz_store_address' => $params['biz_store_address'],
                        'store_entrance_pic' => [
                            $params['store_entrance_pic']
                        ],
                        'indoor_pic' => [
                            $params['indoor_pic']
                        ]
                    ]
                ]
            ],
            'settlement_info' => [
                'settlement_id' => $params['settlement_id'] . '',
                'qualification_type' => $params['qualification_type'],
                'qualifications' => !empty($params['qualifications']) ? $params['qualifications'] : [],
                'activities_id' => $params['activities_rate'] ? '20191030111cff5b5e' : '',
                'activities_rate' => $params['activities_rate']
            ],
            'bank_account_info' => [
                'bank_account_type' => $params['bank_account_type'],
                'account_name' => $this->Encrypt($params['account_name']),
                'account_bank' => $params['account_bank'],
                'bank_address_code' => $params['bank_address_code'],
                'bank_name' => isset($params['bank_name']) ? $params['bank_name'] : '',
                'account_number' => $this->Encrypt($params['account_number'])
            ]
        ];

        file_put_contents('./jinjian.txt', json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n", 8);

        // 获取私钥
        $mch_private_key = $this->get_Privatekey();
        // 签名
        $sign = $this->get_Sign($url, "POST", json_encode($data), $mch_private_key, $this->serial_no);

        $public_serial_no = $this->get_Certificates();
        // 请求头
        $header[] = 'User-Agent:' . $_SERVER['HTTP_USER_AGENT'];
        $header[] = 'Accept:application/json';
        $header[] = 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $sign;
        $header[] = 'Content-Type:application/json;charset=utf-8';
        $header[] = 'Wechatpay-Serial:' . $public_serial_no;
//        print_r(json_encode($data));exit;
        $info = $this->http_Request($url, $header, json_encode($data));

        file_put_contents('./jinjian.txt', $info . " <\n\n", 8);

        $info = json_decode($info, TRUE, 512, JSON_BIGINT_AS_STRING);

        if (isset($info['code'])) {
            return [
                'errno' => 1,
                'message' => $info['message']
            ];
        } else {
            return [
                'errno' => 0,
                'applyment_id' => $info['applyment_id']
            ];
        }
    }

    /**
     * enquiryOfApplyStatus 入驻申请状态查询
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function enquiryOfApplyStatus(array $params)
    {
        if (!isset($params['applyment_id']) && !isset($params['business_code'])) {
            throw new WxException(20004);
        }
        $url = self::WXAPIHOST . '/applyment4sub/applyment/applyment_id/' . $params['applyment_id'];

        //获取私钥
        $mch_private_key = $this->get_Privatekey();
        // 签名
        $sign = $this->get_Sign($url, "GET", '', $mch_private_key, $this->serial_no);

        $header[] = 'User-Agent:' . $_SERVER['HTTP_USER_AGENT'];
        $header[] = 'Accept:application/json';
        $header[] = 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $sign;
        $header[] = 'Content-Type:application/json;charset=utf-8';
        $result = $this->http_Request($url, $header);
        $info = json_decode($result, TRUE, 512, JSON_BIGINT_AS_STRING);
        return $info;
    }

    /**
     * 企业付款到用户零钱
     * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
     * @param float $totalFee 收款总费用 单位元
     * @param string $outTradeNo 唯一的订单号
     * @param string $orderName 订单名称
     * @param string $notifyUrl 支付结果通知url 不要有问号
     * @param string $timestamp 支付时间
     * @return string
     */
    public function createJsBizPackage($openid, $totalFee, $outTradeNo)
    {
        $config = array(
            'mch_id' => $this->mch_id,
            'appid' => $this->appid,
            'key' => $this->aes_key,
        );
        $unified = array(
            'mch_appid' => $config['appid'],
            'mchid' => $config['mch_id'],
            'nonce_str' => $this->getRandChar(),
            'openid' => $openid,
            'check_name' => 'NO_CHECK',        //校验用户姓名选项。NO_CHECK：不校验真实姓名，FORCE_CHECK：强校验真实姓名
            //'re_user_name'=>$trueName,                 //收款用户真实姓名（不支持给非实名用户打款）
            'partner_trade_no' => $outTradeNo,
            'spbill_create_ip' => '127.0.0.1',
            'amount' => intval($totalFee * 100),       //单位 转为分
            'desc' => '提现',            //企业付款操作说明信息
        );
        $unified['sign'] = $this->makeSign($unified, 'md5');

        //$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', self::arrayToXml($unified));
        $url = self::WXAPIHOST . 'mmpaymkttransfers/promotion/transfers';

        $xml = $this->toXml($unified);
        // 发起请求
        $res = $this->httpsRequest($url, $xml, [], true);

        $rt = $this->disposeReturn($res, [
            'partner_trade_no',
            'payment_no',
            'payment_time',
        ]);

        return $rt;
    }

    /**
     * getBusinessCode 生成业务申请编号
     * @return mixed|null|string|string[]
     */
    public function getBusinessCode()
    {
        $millisecond = $this->getMillisecond();
        return mb_strtoupper(md5(uniqid($millisecond . mt_rand())));
    }

    /**
     * accountNumberIsSupport 判断银行卡账号是否支持
     * @param $account_number
     * @return bool
     */
    private function accountNumberIsSupport(string $account_number)
    {

        $account_prefix_6 = substr($account_number, 0, 6);
        $account_prefix_8 = substr($account_number, 0, 8);
        $not_support = ['623501', '621468', '620522', '625191', '622384', '623078', '940034', '622150', '622151', '622181', '622188', '955100', '621095', '620062', '621285', '621798', '621799', '621797', '622199', '621096', '62215049', '62215050', '62215051', '62218849', '62218850', '62218851', '621622', '623219', '621674', '623218', '621599', '623698', '623699', '623686', '621098', '620529', '622180', '622182', '622187', '622189', '621582', '623676', '623677', '622812', '622810', '622811', '628310', '625919', '625368', '625367', '518905', '622835', '625603', '625605', '518905'];
        if (array_search($account_prefix_6, $not_support)) {
            return true;
        }
        if (array_search($account_prefix_8, $not_support)) {
            return true;
        }
        return false;
    }

    /**
     * checkParams 校验入驻接口必填字段信息
     * @param array $params
     * @return bool
     */
    private function checkParams(array $params)
    {
        $data = ['id_card_copy', 'id_card_national', 'id_card_name', 'id_card_number', 'id_card_valid_time', 'id_card_valid_time1', 'account_name', 'account_bank', 'bank_address_code', 'account_number', 'micro_name', 'store_address_code', 'merchant_shortname', 'service_phone', 'contact_name', 'contact_phone'];
        $result = true;
        foreach ($data as $key => $value) {
            if (!isset($params[$value]) || empty($params[$value])) {
                $result = false;
                break;
            }
        }
        return $result;
    }

    /**
     * tenantConfig  关注配置  小微商户关注功能配置API
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function tenantConfig(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        $data = [
            'mch_id' => $this->mch_id,
            'sub_mch_id' => $params['sub_mch_id'],
            'nonce_str' => $this->getRandChar(),
            'sign_type' => 'HMAC-SHA256',
            'sign' => '',
            'sub_appid' => $params['sub_appid'] ? $params['sub_appid'] : 'NULL',
            'subscribe_appid' => $params['subscribe_appid'] ? $params['subscribe_appid'] : '',
            'receipt_appid' => $params['receipt_appid'] ? $params['receipt_appid'] : '',
        ];
        $data['sign'] = $this->makeSign($data, $data['sign_type']);
        $url = self::WXAPIHOST . 'secapi/mkt/addrecommendconf';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        return $this->disposeReturn($res, ['subscribe_appid', 'receipt_appid']);
    }

    /**
     * payTheDirectoryConfig  支付目录配置   小微商户开发配置新增支付目录API
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function payTheDirectoryConfig(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        if (!isset($params['jsapi_path'])) {
            throw new WxException(20004, '授权目录必填');
        }
        if (!isset($params['appid'])) {
            throw new WxException(20004, '服务商的公众账号 ID 必填');
        }
        $data = [
            'appid' => $params['appid'],
            'mch_id' => $this->mch_id,
            'sub_mch_id' => $params['sub_mch_id'],
            'jsapi_path' => $params['jsapi_path'],
            'sign' => '',
        ];
        $data['sign'] = $this->makeSign($data, 'md5');
        $url = self::WXAPIHOST . 'secapi/mch/addsubdevconfig';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        return $this->disposeReturn($res);
    }

    /**
     * bindAppIdConfig 绑定appid配置  小微商户新增对应APPID关联API
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function bindAppIdConfig(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        if (!isset($params['sub_appid'])) {
            throw new WxException(20004, '关联 APPID 必填');
        }
        if (!isset($params['appid'])) {
            throw new WxException(20004, '服务商的公众账号 ID 必填');
        }
        $data = [
            'appid' => $params['appid'],
            'mch_id' => $this->mch_id,
            'sub_mch_id' => $params['sub_mch_id'],
            'sub_appid' => $params['sub_appid'],
            'sign' => '',
        ];
        $data['sign'] = $this->makeSign($data, 'md5');
        $url = self::WXAPIHOST . 'secapi/mch/addsubdevconfig';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        return $this->disposeReturn($res);
    }

    /**
     * inquireConfig 查询配置
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function inquireConfig(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        if (!isset($params['appid'])) {
            throw new WxException(20004, '服务商的公众账号 ID 必填');
        }
        $data = [
            'mch_id' => $this->mch_id,
            'sub_mch_id' => $params['sub_mch_id'],
            'sign' => '',
            'appid' => $params['appid'],
        ];
        $data['sign'] = $this->makeSign($data, 'md5');
        $url = self::WXAPIHOST . 'secapi/mch/querysubdevconfig';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        $rt = $this->disposeReturn($res, ['jsapi_path_list', 'appid_config_list']);
        $rt['jsapi_path_list'] = json_decode($rt['jsapi_path_list'], true);
        $rt['appid_config_list'] = json_decode($rt['appid_config_list'], true);
        return $rt;
    }

    /**
     * modifyArchives 小微商户修改资料接口-修改结算银行卡
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function modifyArchives(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }

        $data = [
            'version' => '1.0',
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->getRandChar(),
            'sign_type' => 'HMAC-SHA256',
            'sub_mch_id' => $params['sub_mch_id'],
            'sign' => '',
            'account_number' => isset($params['account_number']) ? $this->publicKeyEncrypt($params['account_number']) : '',
            'bank_name' => $params['bank_name'] ? $params['bank_name'] : '',
            'account_bank' => $params['account_bank'] ? $params['account_bank'] : '',
            'bank_address_code' => $params['bank_address_code'] ? $params['bank_address_code'] : '',
            //'cert_sn' => $this->newResponseData()['serial_no'],
            'cert_sn' => $this->serial_no,
        ];
        $data['sign'] = $this->makeSign($data, $data['sign_type']);
        $url = self::WXAPIHOST . 'applyment/micro/modifyarchives';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        return $this->disposeReturn($res, ['sub_mch_id']);
    }

    /**
     * withdrawalState 服务商帮小微商户查询自动提现 - 查询提现状态
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function withdrawalState(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        if (!isset($params['date'])) {
            throw new WxException(20004, '日期必填');
        }

        $data = [
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->getRandChar(),
            'sign_type' => 'HMAC-SHA256',
            'sub_mch_id' => $params['sub_mch_id'],
            'sign' => '',
            'date' => $params['date'],
        ];
        $data['sign'] = $this->makeSign($data, $data['sign_type']);
        $url = self::WXAPIHOST . 'fund/queryautowithdrawbydate';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        $rt = $this->disposeReturn($res, [
            'date',
            'sub_mch_id',
            'withdraw_status',
            'fail_reason',
            'withdraw_id',
            'amount',
            'create_time',
            'success_time',
            'refund_time',
        ]);
        $rt['withdraw_status_desc'] = $this->withdrawStatusDesc($rt['withdraw_status']);
        return $rt;
    }

    /**
     * withdrawStatusMsg 提现状态单据状态字段的中文描述
     * @param $key
     * @return mixed|string
     */
    private function withdrawStatusDesc($key)
    {
        $status = [
            'PROCESSING' => '提现处理中',
            'SUCCESS' => '提现操作成功',
            'REFUNDED' => '银行处理失败，提现操作退票',
            'SUPPORT_RE_WITHDRAW' => '可重新发起提现',
            'SUPPORT_WITHDRAW' => '当日无提现单，并且当日净交易额大于0，因此支持发起该日自动提现',
            'NOT_SUPPORT_WITHDRAW' => '当日距今超过30天；或当日无提现单，并且当日净交易额不大于0，因此不支持发起该日自动提现',
            'NO_WITHDRAW_AUTH' => '商户无提现权限',
        ];
        return $status[$key] ? $status[$key] : '';
    }

    /**
     * reAutoWithdrawByDate 重新发起提现 - 服务商帮小微商户重新发起自动提现
     * @param array $params
     * @return array
     * @throws WxException
     */
    public function reAutoWithdrawByDate(array $params)
    {
        if (!isset($params['sub_mch_id'])) {
            throw new WxException(20004, '小微商户号必填');
        }
        if (!isset($params['date'])) {
            throw new WxException(20004, '日期必填');
        }

        $data = [
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->getRandChar(),
            'sign_type' => 'HMAC-SHA256',
            'sub_mch_id' => $params['sub_mch_id'],
            'sign' => '',
            'date' => $params['date'],
        ];
        $data['sign'] = $this->makeSign($data, $data['sign_type']);
        $url = self::WXAPIHOST . 'fund/reautowithdrawbydate';
        $xml = $this->toXml($data);
        // 发起入驻申请请求
        $res = $this->httpsRequest($url, $xml, [], true);
        // 处理返回值
        return $this->disposeReturn($res, [
            'date',
            'sub_mch_id',
            'withdraw_id',
            'amount',
            'create_time',
        ]);
    }

    /**
     * getApplyEnterList 获取入驻列表
     * @param array $params
     * @return array
     * @author   liuml  <liumenglei0211@163.com>
     * @DateTime 2018/9/19  15:20
     */
    public function getApplyEnterList(array $params)
    {
        $pagesize = isset($params['page_size']) ? $params['page_size'] ?: 20 : 20;
        $applyment_state = isset($params['applyment_state']) ? $params['applyment_state'] : '';
        $applyment_id = isset($params['applyment_id']) ? $params['applyment_id'] : '';
        $contact_phone = isset($params['contact_phone']) ? $params['contact_phone'] : '';
        // 组装条件
        $condition = [];

        if ($applyment_state) {
            $condition['applyment_state'] = $applyment_state;
        }
        if ($applyment_state) {
            $condition['applyment_id'] = $applyment_id;
        }
        if ($contact_phone) {
            $condition['contact_phone'] = $contact_phone;
        }
        $xw_apply_enter = new XwApplyEnter();
        $data = $xw_apply_enter->select('id', 'store_name', 'contact', 'contact_phone', 'applyment_id', 'applyment_state_msg as applyment_state', 'sub_mch_id', 'created_at')->where($condition)->orderBy('created_at', 'desc')->paginate($pagesize);
        $res = collect($data->items())->toArray();
        $rt = array_map(function ($v) {
            $v['created_at'] = date('Y-m-d H:i:s', $v['created_at']);
            return $v;
        }, $res);
        return $rt;
    }

    /**
     * setShowImgUrl 设置图片链接
     * @param $imgs
     * @return false|\Illuminate\Contracts\Routing\UrlGenerator|string
     * @author   liuml  <liumenglei0211@163.com>
     * @DateTime 2018/9/19  15:53
     */
    public function setShowImgUrl($imgs)
    {
        if (is_string($imgs)) {
            $imgs ? $imgs : 'default';
            $imgs = url("/api/showimg/{$imgs}");
        }
        if (is_array($imgs)) {
            array_map(function ($v) {
                return url("/api/showimg/{$v}");
            }, $imgs);
            $imgs = json_encode($imgs);
        }
        return $imgs;
    }

    /**
     * getBusiness 获取类目中文意思
     * @param $business
     * @return mixed
     * @author   liuml  <liumenglei0211@163.com>
     * @DateTime 2018/9/20  12:10
     */
    public function getBusiness($business)
    {
        $str = '{ "116": "运动户外(线下零售)", "123": "计生用品(线下零售)", "148": "运动健身场馆(休闲娱乐)", "209": "便利店(线下零售)", "292": "食品生鲜(线下零售)[需要特殊资质:1.销售食用农产品：无需特殊资质2.销售加工非食用农产品需提供：《食品流通许可证》或《食品卫生许可证》或《食品经营许可证》或《保健食品经营卫生许可证》（四选一）]", "293": "家具建材/家居厨具(线下零售)", "294": "美妆个护(线下零售)", "295": "礼品鲜花/农资绿植(线下零售)", "296": "汽车用品(线下零售)", "297": "服饰箱包(线下零售)", "298": "钟表眼镜(线下零售)", "299": "婚庆/摄影(居民生活/商业服务)", "300": "俱乐部/休闲会所(休闲娱乐)", "301": "旅馆/酒店/度假区(交通运输/票务旅游)", "305": "宠物/宠物用品(线下零售)", "306": "装饰/设计(居民生活/商业服务)", "307": "娱乐票务(交通运输/票务旅游)", "319": "数码电器/电脑办公(线下零售)", "320": "家政/维修服务(居民生活/商业服务)", "321": "广告/会展/活动策划(居民生活/商业服务)", "323": "图书音像/文具乐器(线下零售)", "324": "苗木种植/园林绿化(居民生活/商业服务)", "551": "其他中餐(餐饮)", "552": "西餐(餐饮)", "553": "日韩/东南亚菜(餐饮)", "554": "咖啡厅(餐饮)", "555": "火锅(餐饮)", "556": "烧烤(餐饮)", "557": "快餐(餐饮)", "560": "小吃/熟食(餐饮)", "561": "烘焙糕点(餐饮)", "562": "甜品饮品(餐饮)", "577": "酒吧(休闲娱乐)", "580": "美发/美容/美甲店(休闲娱乐)[需要特殊资质:如涉及医疗美容技术内容需提供《医疗机构执业许可证》]", "586": "批发业(线下零售)[需要特殊资质:一、食盐批发：食盐批发许可证+国务院盐业主管机构备案证明文件 二、医疗器械批发：批发第二类医疗器械需取得食品药品监督管理部门备案证明；批发第三类医疗器械需取得《医疗器械经营许可证》 三、批发报纸、期刊、图书、音像制品、电子出版物等：《出版物经营许可证》]" }';
        $arr = json_decode($str, true);
        return $arr[$business];
    }

    /**
     * getStoreAddress 传code获取中文地址
     * @param $store_address_code
     * @return mixed
     * @author   liuml  <liumenglei0211@163.com>
     * @DateTime 2018/9/20  12:11
     */
    public function getStoreAddress($store_address_code)
    {
        $jsonStr = file_get_contents('/json/cityCode.json');
        $arr = json_decode($jsonStr, true);
        return $arr[$store_address_code];
    }

}
